package com.estate.system.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.estate.common.core.domain.AjaxResult;
import com.estate.common.core.domain.entity.SysUser;
import com.estate.common.core.domain.entity.TransactionData;
import com.estate.common.core.domain.model.Pagination;
import com.estate.common.core.domain.req.TransactionDataReq;
import com.estate.common.utils.PageOutPutBean;
import com.estate.common.utils.PageQuery;
import com.estate.common.utils.SnowflakeIdWorker;
import com.estate.common.utils.TimeZoneUtils;
import com.estate.common.utils.bean.BeanUtils;
import com.estate.system.domain.report.boss.PropertyTypeDistribution;
import com.estate.system.domain.report.boss.TransactionTypeDistribution;
import com.estate.system.domain.report.boss.agentperformance.AgentStats;
import com.estate.system.domain.report.boss.agentperformance.ChartData;
import com.estate.system.domain.report.boss.listing.PriceRangeDistribution;
import com.estate.system.domain.vo.AgentPropertyDistributionResult;
import com.estate.system.listener.SalesDataExcelListener;
import com.estate.system.mapper.SysUserMapper;
import com.estate.system.mapper.TransactionDataMapper;
import com.estate.system.service.ITransactionDataService;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class TransactionDataServiceImpl extends ServiceImpl<TransactionDataMapper, TransactionData> implements ITransactionDataService {

    private static final Logger log = LoggerFactory.getLogger(TransactionDataServiceImpl.class);

    @Resource
    private TransactionDataServiceImpl transactionDataService;
    @Resource
    private TransactionDataMapper transactionDataMapper;
    @Resource
    private SysUserMapper  userMapper;

    @Override
    public AjaxResult importSalesData(MultipartFile file) {

        //生成一个当前悉尼时间
        LocalDateTime now = TimeZoneUtils.now();

        //生成一个导入唯一ID
        Long importId = SnowflakeIdWorker.getSingleton().nextId();

        List<String> errCache = Lists.newArrayList();

        // 读取Excel数据
        SalesDataExcelListener listener = new SalesDataExcelListener();
        EasyExcel.read(readExcel(file), TransactionDataReq.class, listener)
                .ignoreEmptyRow(true).autoTrim(true).sheet(0, null).headRowNumber(2).doRead();
        List<TransactionDataReq> reqs = listener.getData();

        // 异常处理
        errCache.addAll(listener.CHECKLIST);
        if (!ObjectUtils.isEmpty(errCache)) {
            log.error("导入的错误数据： {}", JSONObject.toJSONString(errCache));
            int total = reqs.size() + errCache.size();
            int succCount = reqs.size();
            int errorCount = errCache.size();
            errCache.add(0, "Total: " + total + " entries; Validation successful: " + succCount + " entries; Validation failed: " + errorCount+ " entries");
            return AjaxResult.error("Import completed", errCache);
        }

        // 构建数据
        reqs = reqs.stream().distinct().collect(Collectors.toList());

        List<TransactionData> entities = Lists.newArrayList();
        for (TransactionDataReq req : reqs) {
            TransactionData transactionData = new TransactionData();
            transactionData.setId(SnowflakeIdWorker.getSingleton().nextId());
            BeanUtils.copyProperties(req, transactionData);
            String listingType = req.getListingType();
            //根据“ or ”,或者“ OR ”“,”或者“，”或者“ ”或者“or”或者作为分隔符切分listingType,并转为List
            String[] listingTypes = listingType.split("\\s+(?:or|OR)\\s+|\\s*[,，]\\s*|\\s+");
            List<String> listingTypeList = Lists.newArrayList(listingTypes);
            transactionData.setListingType(JSONObject.toJSONString(listingTypeList));
            /**
             * 添加导入ID
             */
            transactionData.setImportId(importId);
            transactionData.setIsValid(false);
            transactionData.setImportedAt(now);
            entities.add(transactionData);
        }
        transactionDataService.saveBatch(entities);
        return AjaxResult.success("Import data completed", importId + "");
    }

    @Override
    public PageOutPutBean<TransactionData> preViewImportSalesData(String importId, PageQuery pageQuery) {
        if (ObjectUtils.isEmpty(pageQuery) || ObjectUtils.isEmpty(pageQuery.getPageIndex()) || pageQuery.getPageIndex() <= 0) {
            pageQuery.setPageIndex(1);
        }
        if (ObjectUtils.isEmpty(pageQuery) || ObjectUtils.isEmpty(pageQuery.getPageSize()) || pageQuery.getPageSize() <= 0) {
            pageQuery.setPageSize(10);
        }

        Page page = new Page<>(pageQuery.getPageIndex(), pageQuery.getPageSize());
        QueryWrapper<TransactionData> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(TransactionData::getImportId, Long.valueOf(importId));

        IPage<TransactionData> transactionDataList = transactionDataService.page(page, queryWrapper);
        return pageTransform2PageOutPutBean(transactionDataList);
    }

    public static PageOutPutBean pageTransform2PageOutPutBean(IPage result) {
        PageOutPutBean pageOutPutBean = new PageOutPutBean();
        pageOutPutBean.setData(result.getRecords());
        Pagination pb = new Pagination();
        pb.setPageNumber(result.getCurrent());
        pb.setPageSize(result.getSize());
        pb.setTotalPages(result.getPages());
        pb.setTotalRecords(result.getTotal());
        pageOutPutBean.setPagination(pb);
        return pageOutPutBean;
    }

    @Override
    public AjaxResult saveImportSalesData(String importId) {
        QueryWrapper<TransactionData> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(TransactionData::getImportId, Long.valueOf(importId));
        List<TransactionData> transactionDataList = transactionDataService.list(queryWrapper);
        transactionDataList.forEach(transactionData -> transactionData.setIsValid(true));
        transactionDataService.updateBatchById(transactionDataList);
        return AjaxResult.success("Save data request completed");
    }

    @Override
    public AjaxResult extraInfoOfSalesData() {
        Map<String, Object> resultParams = Maps.newHashMap();
        //根据importedAt倒序排，并获取时间最大的一条记录
        QueryWrapper<TransactionData> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().orderByDesc(TransactionData::getImportedAt).last("limit 1");
        TransactionData transactionData = transactionDataService.getOne(queryWrapper);

        if (transactionData != null && transactionData.getImportedAt() != null) {
            Long importId = transactionData.getImportId();
            //根据importId统计总记录数
            QueryWrapper<TransactionData> countQueryWrapper = new QueryWrapper<>();
            countQueryWrapper.lambda().eq(TransactionData::getImportId, importId);
            long total = transactionDataService.count(countQueryWrapper);
            resultParams.put("lastImportSize", total);
            //将transactionData.getImportedAt()转为字符串时间
            LocalDateTime dateTime = LocalDateTime.parse(transactionData.getImportedAt()+"");
            ZoneId sydneyZone = ZoneId.of("Australia/Sydney");
            ZonedDateTime sydneyTime = dateTime.atZone(ZoneId.systemDefault())
                    .withZoneSameInstant(sydneyZone);
            DateTimeFormatter noMicroFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            //String time = TimeZoneUtils.formatDisplayTime(transactionData.getImportedAt());
            resultParams.put("lastImportedAt", sydneyTime.format(noMicroFormatter));
            resultParams.put("lastImportedId", transactionData.getImportId());
            return AjaxResult.success("Retrieve data request completed", resultParams);
        }
        return AjaxResult.success("Retrieve data request completed", resultParams);
    }

    @Override
    public Map<String, Object> getTransactions(Map<String, Object> param) {
            log.info("获取近七天新增交易量请求参数={}", param);
            Map<String, Object> result = new HashMap<>();
            try {
                // 获取悉尼（澳大利亚东部）的当前时间
                ZoneId australiaSydney = ZoneId.of("Australia/Sydney");
                ZonedDateTime now = ZonedDateTime.now(australiaSydney);
                // 计算7天前的时间
                int sevenDays = param.get("XDays") == null ? 7 : Integer.parseInt(param.get("XDays").toString());
                ZonedDateTime sevenDaysAgo = now.minusDays(sevenDays);

                // 计算14天前的时间
                ZonedDateTime fourteenDaysAgo = now.minusDays(sevenDays * 2L);

                SysUser sysUser = new SysUser();
                List<String> emailList = userMapper.selectUserList(sysUser).stream().map(SysUser::getEmail).collect(Collectors.toList());

                // 设置日期时间格式化器
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                Long sevenDaysAgoCount = transactionDataMapper.getTransaction(sevenDaysAgo.format(formatter), now.format(formatter),emailList);
                Long fourteenDaysAgoCount = transactionDataMapper.getTransaction(fourteenDaysAgo.format(formatter), sevenDaysAgo.format(formatter),emailList);

                result.put("sevenDaysAgoCount", sevenDaysAgoCount);
                result.put("fourteenDaysAgoCount", fourteenDaysAgoCount);
                if (null == sevenDaysAgoCount || sevenDaysAgoCount == 0) {
                    result.put("addPercentage", 0d);
                }
                if (null == fourteenDaysAgoCount || fourteenDaysAgoCount == 0) {
                    result.put("addPercentage", 100d);
                }
                //获取环比
                if (null != fourteenDaysAgoCount && fourteenDaysAgoCount !=0  && null != sevenDaysAgoCount ) {
                    double addPercentage = (double) (sevenDaysAgoCount - fourteenDaysAgoCount) / fourteenDaysAgoCount;
                    result.put("addPercentage", addPercentage);
                }
            } catch (Exception e) {
                log.error("获取近七天新增交易量请求参数......", e);
            }
            return result;
        }


    /**
     * 转换文件流
     *
     * @param file 文件
     * @return Excel 数据 list
     */
    private InputStream readExcel(MultipartFile file) {
        byte[] byteArr = new byte[0];
        try {
            byteArr = file.getBytes();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return new ByteArrayInputStream(byteArr);
    }

    public List<TransactionTypeDistribution> generateTransactionTypeData(Map<String, Object> paramData) {
        List<TransactionTypeDistribution> transactionTypeDistributions = new ArrayList<>();
        SysUser sysUser = new SysUser();
        List<String> emailList = userMapper.selectUserList(sysUser).stream().map(SysUser::getEmail).collect(Collectors.toList());
        List<Map<String,Object>> transactionTypeList  = transactionDataMapper.generateTransactionTypeData(paramData,emailList);
        transactionTypeList.forEach(transactionType->{
            transactionTypeDistributions.add(new TransactionTypeDistribution(transactionType.get("listingtype").toString(), Double.parseDouble(transactionType.get("percentage").toString())));
        });

        return transactionTypeDistributions;
    }

    public ChartData createTransactionType(Map<String, Object> paramData) {
        ChartData chartData = new ChartData();
        SysUser sysUser = new SysUser();
        List<String> emailList = userMapper.selectUserList(sysUser).stream().map(SysUser::getEmail).collect(Collectors.toList());
        List<AgentPropertyDistributionResult> agentAndListingPropertyList = transactionDataMapper.createTransactionType(paramData, emailList);
        Map<String, List<AgentPropertyDistributionResult>> resultMap = agentAndListingPropertyList.stream()
                .collect(Collectors.toMap(
                        AgentPropertyDistributionResult::getAgentName, // key映射
                        item -> {
                            List<AgentPropertyDistributionResult> list = new ArrayList<>();
                            list.add(item);
                            return list;
                        }, // value映射
                        (existingList, newList) -> { // 合并函数（处理key冲突）
                            existingList.addAll(newList);
                            return existingList;
                        }
                ));
        resultMap.forEach((agentName, agentPropertyDistributionResultList) -> {
            AgentStats agent = new AgentStats("agentName");
            for (AgentPropertyDistributionResult agentPropertyDistributionResult : agentPropertyDistributionResultList) {
                agent.addPropertyType(agentPropertyDistributionResult.getPropertyType(), Integer.parseInt(agentPropertyDistributionResult.getPropertyCount()));
            }
        });
        return chartData;
    }

    public List<PropertyTypeDistribution> generatePropertyTypeData(Map<String, Object> paramData) {
        List<PropertyTypeDistribution> propertyTypeDistributions = new ArrayList<>();
        SysUser sysUser = new SysUser();
        List<String> emailList = userMapper.selectUserList(sysUser).stream().map(SysUser::getEmail).collect(Collectors.toList());
        List<Map<String,Object>> transactionTypeList  = transactionDataMapper.generatePropertyTypeData(paramData,emailList);
        for (Map<String, Object> stringObjectMap : transactionTypeList) {
            propertyTypeDistributions.add(new PropertyTypeDistribution(stringObjectMap.get("type").toString(), Double.parseDouble(stringObjectMap.get("count").toString())));
        }
        return propertyTypeDistributions;
    }

    public List<PriceRangeDistribution> generatePriceRangeData(Map<String, Object> paramData) {
        List<PriceRangeDistribution> priceRangeDistributionList = new ArrayList<>();
        SysUser sysUser = new SysUser();
        List<String> emailList = userMapper.selectUserList(sysUser).stream().map(SysUser::getEmail).collect(Collectors.toList());
        List<Map<String,Object>> transactionTypeList  = transactionDataMapper.generatePriceRangeData(paramData,emailList);
        for (Map<String, Object> stringObjectMap : transactionTypeList) {
            priceRangeDistributionList.add(new PriceRangeDistribution(stringObjectMap.get("pricerange").toString(),Double.parseDouble(stringObjectMap.get("percentage").toString()),Integer.parseInt(stringObjectMap.get("count").toString())));

        }
        return priceRangeDistributionList;
    }
}